package com.nercel.dsj.gksales.api.controller;

import com.nercel.dsj.gksales.exception.ResponseCode;
import com.nercel.dsj.gksales.exception.RestApiException;
import com.nercel.dsj.gksales.model.BalanceRecordType;
import com.nercel.dsj.gksales.model.PayServiceType;
import com.nercel.dsj.gksales.model.PayType;
import com.nercel.dsj.gksales.model.ResponseResult;
import com.nercel.dsj.gksales.model.entity.*;
import com.nercel.dsj.gksales.service.*;
import com.nercel.dsj.gksales.thirdparty.alipay.config.AliPayConfig;
import com.nercel.dsj.gksales.thirdparty.alipay.service.AlipayService;
import com.nercel.dsj.gksales.thirdparty.wxpay.entity.WxPrePayItem;
import com.nercel.dsj.gksales.thirdparty.wxpay.service.WxPayService;
import com.nercel.dsj.gksales.thirdparty.wxpay.util.WXUtil;
import com.nercel.dsj.gksales.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;

@Slf4j
@RestController
@Api(tags="支付接口")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PayApiController extends BaseApiController {

    private final AlipayService alipayService;

    private final AgentService agentService;

    private final WxPayService wxPayService;

    private final PaymentService paymentService;

    private final UserService userService;

    private final UrlService urlService;

    private final SellRecordService sellRecordService;

    private final BalanceRecordService balanceRecordService;

    private final ProductService productService;

    private final ConfigurationService configurationService;

    private Double getVipPrice(String phone, Double price){
        //测试帐号
        if(phone != null && phone.length() == 11
                && "18602756630,17012341354,13972659490,10000000000,18400000000,17012341354".contains(phone)){
            return 0.01;
        }
//        if(isProd()){
//            //VIP价格
//            return Double.valueOf(configurationService.getAsInteger(Conf.AGENT_VIP_PRICE));
//        }
        return price;
    }

    @ApiOperation(value = "开通VIP/支付宝/H5支付")
    @GetMapping(value="/api/v1/vip/alipay/h5")
    public void createPreOrderForH5(
            HttpServletRequest request, HttpServletResponse response,
            @ApiParam(value = "销售员手机号") @RequestParam String salesPhone,
            @ApiParam(value = "用户手机号") @RequestParam String phone,
            @ApiParam(value = "商品UID") @RequestParam String puid,
            @ApiParam(value = "自己支付（代付false)") @RequestParam(defaultValue = "true") Boolean self,
            @ApiParam(value = "支付成功返回URL(safebase64编码)") @RequestParam String backUrl
    ){
        log.info(backUrl);
        log.info(SafeBase64.safeUrlBase64Decode(backUrl));
        if(puid == null){
            throw new RestApiException(ResponseCode.PRODUCT_NOT_FOUND);
        }
        Product product = productService.findByUid(puid);
        if(product == null){
            throw new RestApiException(ResponseCode.PRODUCT_NOT_FOUND);
        }
        String subject = "高考U选VIP帐号";
        Double price = getVipPrice(self ? phone : salesPhone, Double.valueOf(product.getPrice())/100);
        String outTradeNo = UuidUtil.get32UUID();
        String notifyUrl = url("api/v1/alipay/callback");
        System.out.println("notifyUrl: " + notifyUrl);
        String encodeBackUrl = urlService.generateUrl(SafeBase64.safeUrlBase64Decode(backUrl));
        try {
            User sales = userService.findByPhone(salesPhone);
            Payment payment = new Payment();
            payment.setOrderNumber(outTradeNo);
            payment.setSuccessful(false);
            payment.setAmount(Double.valueOf(price * 100).intValue());
            payment.setCount(1);
            payment.setCreatedTime(new Date());
            payment.setType(PayType.ALI_PAY);
            payment.setUserId(self || sales == null ? null : sales.getId());
            payment.setUserPhone(self ? phone : salesPhone);
            payment.setSalesPhone(salesPhone);
            payment.setValue1(phone);   //value1存储被开通手机号
            payment.setServiceType(self ? PayServiceType.USER_BUY_VIP : PayServiceType.SALES_BUY_VIP);
            paymentService.save(payment);
            alipayService.createPreOrderForH5(outTradeNo,price,subject,notifyUrl,encodeBackUrl,request,response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @ApiOperation(value = "二维码支付宝支付回调", hidden = true)
    @RequestMapping(value="/api/v1/alipay/callback", method= RequestMethod.POST)
    public String aliPayCallBackForQrCode(HttpServletRequest request, HttpServletResponse response){
        log.info("alipay callback : ");
        Map<String,String> params = alipayService.getAliPayCallBackParam(request);
        String checkResult = alipayService.checkCallbackParam(params);
        return this.doServiceAfterAliCheckSuccess(checkResult,params);
    }

    @ApiOperation(value = "开通VIP/微信/H5支付")
    @RequestMapping(value="/api/v1/vip/wxpay/h5", method= RequestMethod.GET)
    public WxPrePayItem createWxPayPreOrderForH5(
            HttpServletRequest request,
            HttpServletResponse response,
            @ApiParam(value = "销售员手机号") @RequestParam String salesPhone,
            @ApiParam(value = "用户手机号") @RequestParam String phone,
            @ApiParam(value = "商品UID") @RequestParam String puid,
            @ApiParam(value = "自己支付（代付false)") @RequestParam(defaultValue = "true") Boolean self,
            @ApiParam(value = "支付成功返回URL(safebase64编码)") @RequestParam String backUrl
    ){
        String ipStr = isProd() ? IpUtil.getUserIp(getRequest()) : IpUtil.getIpFromSohu();
        log.info("wxpay ipStr: " + ipStr);
        String productId = "gk-vip-consume-h5";
        if(puid == null){
            throw new RestApiException(ResponseCode.PRODUCT_NOT_FOUND);
        }
        Product product = productService.findByUid(puid);
        if(product == null){
            throw new RestApiException(ResponseCode.PRODUCT_NOT_FOUND);
        }
        Double price = getVipPrice(self ? phone : salesPhone, Double.valueOf(product.getPrice())/100);
        String outTradeNo = UuidUtil.get32UUID();
        String notifyUrl = url("api/v1/vip/wxpay/callback");
        System.out.println("notifyUrl: " + notifyUrl);
        try {
            User sales = userService.findByPhone(salesPhone);
            Payment payment = new Payment();
            payment.setOrderNumber(outTradeNo);
            payment.setSuccessful(false);
            payment.setAmount(Double.valueOf(price * 100).intValue());
            payment.setCount(1);
            payment.setCreatedTime(new Date());
            payment.setType(PayType.WEI_XIN);
            payment.setUserId(self ? null : sales.getId());
            payment.setUserPhone(self || sales == null ? phone : salesPhone);
            payment.setSalesPhone(salesPhone);
            payment.setValue1(phone);   //value1存储被开通手机号
            payment.setServiceType(self ? PayServiceType.USER_BUY_VIP : PayServiceType.SALES_BUY_VIP);
            paymentService.save(payment);
            WxPrePayItem preOrderResponse = wxPayService.createPreOrderForH5(ipStr, notifyUrl, productId, outTradeNo, price);
            preOrderResponse.setOutTradeNo(outTradeNo);
            if(backUrl != null){
                preOrderResponse.setPayUrl(preOrderResponse.getPayUrl() + "&redirect_url=" + EncodingUtil.encodeURIComponent(SafeBase64.safeUrlBase64Decode(backUrl)));
            }
            return preOrderResponse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @ApiOperation(value = "微信公众号内支付")
    @GetMapping(value="/api/v1/vip/wxpay/jsapi")
    public WxPrePayItem createWxPayPreOrderForWxServerCode(
            @ApiParam(value = "OPENID") @RequestParam String openId,
            @ApiParam(value = "销售员手机号") @RequestParam String salesPhone,
            @ApiParam(value = "用户手机号") @RequestParam String phone,
            @ApiParam(value = "商品UID") @RequestParam String puid,
            @ApiParam(value = "自己支付（代付false)") @RequestParam(defaultValue = "true") Boolean self
    ){
        String ipStr = isProd() ? IpUtil.getUserIp(getRequest()) : IpUtil.getIpFromSohu();
        log.info("wxpay ipStr: " + ipStr);
        if(puid == null){
            throw new RestApiException(ResponseCode.PRODUCT_NOT_FOUND);
        }
        Product product = productService.findByUid(puid);
        if(product == null){
            throw new RestApiException(ResponseCode.PRODUCT_NOT_FOUND);
        }
        Double price = getVipPrice(self ? phone : salesPhone, Double.valueOf(product.getPrice())/100);
        String outTradeNo = UuidUtil.get32UUID();
        String notifyUrl = url("api/v1/vip/wxpay/callback");
        System.out.println("notifyUrl: " + notifyUrl);
        try {
            User sales = userService.findByPhone(salesPhone);
            Payment payment = new Payment();
            payment.setOrderNumber(outTradeNo);
            payment.setSuccessful(false);
            payment.setAmount(Double.valueOf(price * 100).intValue());
            payment.setCount(1);
            payment.setCreatedTime(new Date());
            payment.setType(PayType.WEI_XIN);
            payment.setUserId(self || sales == null ? null : sales.getId());
            payment.setUserPhone(self ? phone : salesPhone);
            payment.setSalesPhone(salesPhone);
            payment.setValue1(phone);   //value1存储被开通手机号
            payment.setServiceType(self ? PayServiceType.USER_BUY_VIP : PayServiceType.SALES_BUY_VIP);
            paymentService.save(payment);
            WxPrePayItem preOrderResponse = wxPayService.createPreOrderForJsApi(openId,ipStr,notifyUrl,outTradeNo,price);
            preOrderResponse.setOutTradeNo(outTradeNo);
            return preOrderResponse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @ApiOperation(value = "二维码微信支付回调", hidden = true)
    @RequestMapping(value = "/api/v1/vip/wxpay/callback", produces = "text/html; charset=utf-8")
    @ResponseBody
    public String wxCallback(HttpServletRequest request) throws Exception{
        log.info("wxpay callback ");
        SortedMap<String,String> parameters = wxPayService.getWxPayCallBackParam(request);
        // 获取返回状态
        String return_code = parameters.get("return_code") != null ? parameters.get("return_code") : "";
        // 业务结果
        String result_code = parameters.get("result_code") != null ? parameters.get("result_code") : "";
        // 验证签名
        if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code) && WXUtil.isTenpaySign(parameters)){
            // 总金额
            Integer total_fee = Integer.parseInt(parameters.get("total_fee") != null ? parameters.get("total_fee") : "0");
            // 微信支付订单号
            String transaction_id = parameters.get("transaction_id") != null ? parameters.get("transaction_id") : "";
            // 商户订单号
            String out_trade_no = parameters.get("out_trade_no") != null ? parameters.get("out_trade_no") : "";
            // 获取订单信息并校验支付金额和订单总金额是否匹配
            synchronized (this){
                Payment payment = paymentService.findByOrderNumber(out_trade_no);
                if (payment != null && payment.getAmount().intValue() == total_fee.intValue()){
                    if (!payment.getSuccessful()) {
                        // 支付成功修改相关业务数据
                        payment.setPayedTime(new Date());
                        payment.setSuccessful(true);
                        payment.setPayedNumber(transaction_id);
                        paymentService.update(payment);
                        sellRecordService.saveAndActivateWithPayment(payment);
                        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>wwxw";
                    }
                }
            }
        }else{
            log.info(parameters.get("return_msg"));
            log.error("回调参数验证失败");
        }
        return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
    }

    //支付宝回调验签成功后执行业务
    private String doServiceAfterAliCheckSuccess(String checkResult, Map<String,String> callBackParamMap){
        if (AliPayConfig.SUCCESS.equals(checkResult)){
            String tradeStatus = callBackParamMap.get("trade_status");
            String appId = callBackParamMap.get("app_id");
            String orderNumber = callBackParamMap.get("out_trade_no");
            String payedNumber = callBackParamMap.get("trade_no");
            Double totalAmount = Double.parseDouble(callBackParamMap.get("total_amount"));
            totalAmount = totalAmount * 100;


            // 校验appId并处理指定支付状态(支付成功)
            if (AliPayConfig.TRADE_SUCCESS.equals(tradeStatus) && AliPayConfig.APP_ID.equals(appId)){
                synchronized (this){
                    Payment payment = paymentService.findByOrderNumber(orderNumber);
                    log.debug("orderNumber: " + orderNumber);
                    if (payment != null && totalAmount.intValue() == payment.getAmount().intValue()){
                        if (!payment.getSuccessful()){
                            payment.setPayedTime(new Date());
                            payment.setSuccessful(true);
                            payment.setPayedNumber(payedNumber);
                            paymentService.update(payment);
                            sellRecordService.saveAndActivateWithPayment(payment);
                            return AliPayConfig.SUCCESS;
                        }
                    }
                }
            }
        }
        return AliPayConfig.FAIL;
    }

    @ApiOperation(value = "支付状态检测", notes = "支付是否成功")
    @GetMapping(value="/api/v1/pay/check")
    public ResponseResult payCheck(@ApiParam(value = "交易编号") @RequestParam String orderNumber) {
        Payment payment = paymentService.findByOrderNumber(orderNumber);
        return ApiResultUtil.success("", payment.getSuccessful());
    }

}
